package com.jsbs.iam.auth.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jsbs.iam.auth.constant.RedisConstants;
import com.jsbs.iam.auth.dto.IamDynamicUserGroupAddDto;
import com.jsbs.iam.auth.dto.IamDynamicUserGroupEditDto;
import com.jsbs.iam.auth.dto.IamDynamicUserGroupFilterRuleAddDto;
import com.jsbs.iam.auth.dto.IamOrgInfoQueryDto;
import com.jsbs.iam.auth.entity.IamUserGroupDynamicFilterRule;
import com.jsbs.iam.auth.feign.IamRoleManagerFeign;
import com.jsbs.iam.auth.mapper.IamDynamicUserGroupManagerMapper;
import com.jsbs.iam.auth.mapper.IamRoleOrgFrameworkRelationMapper;
import com.jsbs.iam.auth.mapper.IamStaticUserGroupManagerMapper;
import com.jsbs.iam.auth.mapper.IamUserGroupDynamicFilterRuleMapper;
import com.jsbs.iam.auth.param.*;
import com.jsbs.iam.auth.service.IamDynamicUserGroupManagerService;
import com.jsbs.iam.auth.service.IamUserTypeService;
import com.jsbs.iam.auth.vo.*;
import com.jsbs.iam.common.core.dto.Result;
import com.jsbs.iam.common.core.utils.Json;
import com.jsbs.iam.common.core.utils.PageHelperTool;
import com.jsbs.iam.common.core.utils.StringUtils;
import com.jsbs.iam.common.redis.service.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @ClassName: DynamicUserGroupManagerServiceImpl
 * @Author: tenghuawei
 * @Date: 2023/1/6 10:31
 * @Description:
 */

@SuppressWarnings("all")
@Slf4j
@Service
public class IamDynamicUserGroupManagerServiceImpl implements IamDynamicUserGroupManagerService {

    @Resource
    private RedissonClient redissonClient;

    @Autowired
    IamDynamicUserGroupManagerMapper iamDynamicUserGroupManagerMapper;

    @Autowired
    IamRoleManagerFeign iamRoleManagerFeign;

    @Autowired
    IamUserTypeService iamUserTypeService;

    @Autowired
    IamUserGroupDynamicFilterRuleMapper iamUserGroupDynamicFilterRuleMapper;

    @Autowired
    IamStaticUserGroupManagerMapper iamStaticUserGroupManagerMapper;

    @Autowired
    IamRoleOrgFrameworkRelationMapper iamRoleOrgFrameworkRelationMapper;

    @Value("${_env.name}")
    private String envName;

    /**
     * 功能描述：新增动态用户组
     * @param iamDynamicUserGroupAddDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createDynamicUserGroup(IamDynamicUserGroupAddDto iamDynamicUserGroupAddDto) {
        // 新建动态用户组编码时加锁，失效时间10秒钟
        RLock lock = redissonClient.getLock(RedisConstants.AUTH_DYNAMIC_USER_GROUP_CODE_LOCK);
        Long dynamicUserGroupCode = null;
        try {
            // 5分钟内重试获取锁，10秒后释放
            boolean isLocked = lock.tryLock(5 * 60 * 1000L, 10 * 1000L, TimeUnit.MILLISECONDS);
            // 获取到锁后，进行自增
            if (!isLocked) {
                log.warn("Route=>DynamicUserGroupManagerServiceImpl method=>createDynamicUserGroup  新建动态用户组获取不到锁，生成用户组编码失败，入参为:{}", Json.toJsonString(iamDynamicUserGroupAddDto));
                throw new RuntimeException("获取AUTH_DYNAMIC_USER_GROUP_CODE_LOCK锁失败！");
            }
            // 加锁成功后,获取当前缓存值
            String value = RedisUtils.get(envName + RedisConstants.AUTH_DYNAMIC_USER_GROUP_CODE);
            // 若为空则从数据库取当前最大值+1
            if (StringUtils.isEmpty(value)) {
                dynamicUserGroupCode = Long.valueOf(iamDynamicUserGroupManagerMapper.getMaxDynamicUserGroupCode()) + 1;
            } else {
                // 当前缓存获取成功，并加新增用户数量入缓存
                dynamicUserGroupCode = Long.parseLong(value) + 1;
            }
            // 将最新值更新到缓存中
            RedisUtils.set(envName + RedisConstants.AUTH_DYNAMIC_USER_GROUP_CODE, String.valueOf(dynamicUserGroupCode));
        } catch (Exception e) {
            log.error("Route=>DynamicUserGroupManagerServiceImpl method=>createDynamicUserGroup 新建动态用户组异常:{}, 入参为:{}", e.getMessage(),Json.toJsonString(iamDynamicUserGroupAddDto));
            throw new RuntimeException("新建动态用户组异常!");
        } finally {
            // 手动解锁
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
        AtomicReference<Long> finalCode = new AtomicReference<>(dynamicUserGroupCode);
        iamDynamicUserGroupAddDto.setUserGroupCode("DT" + String.format("%06d", finalCode.getAndSet(finalCode.get())));
        log.info("Route=>DynamicUserGroupManagerServiceImpl method=>createDynamicUserGroup  新建动态用户组 生成用户组编码成功:{}", finalCode.get());
        //新增时，校验用户组名的唯一性
        int count = iamDynamicUserGroupManagerMapper.checkDynamicUserGroupName(iamDynamicUserGroupAddDto.getUserGroupName(),
                iamDynamicUserGroupAddDto.getCompanyCode());
        if(count>0){
            throw new RuntimeException("新增动态用户组时，该用户组名已存在！");
        }

        //选择的用户类型编码
        String userTypeCode = iamDynamicUserGroupAddDto.getUserTypeCode();
        log.info("Route=>DynamicUserGroupManagerServiceImpl method=>createDynamicUserGroup 新建动态用户组时，选择的用户类型编码:{}", userTypeCode);

        //新增数据至动态用户组表
        iamDynamicUserGroupManagerMapper.createDynamicUserGroup(iamDynamicUserGroupAddDto);
        //新增数据至动态用户组规则表
        iamDynamicUserGroupAddDto.getIamUserGroupDynamicFilterRules().forEach(rule ->{
            IamDynamicUserGroupFilterRuleAddDto ruleAddDto = new IamDynamicUserGroupFilterRuleAddDto();
            BeanUtils.copyProperties(rule,ruleAddDto);
            BeanUtils.copyProperties(iamDynamicUserGroupAddDto,ruleAddDto);
            iamUserGroupDynamicFilterRuleMapper.userGroupDynamicFilterRuleAdd(ruleAddDto);
        });

    }

    /**
     * 功能描述：查询动态态用户组
     * @param iamQueryStaticUserGroupParam
     * @return PageInfo
     */
    @Override
    public PageInfo<IamUserGroupVo> queryDynamicUserGroup(IamQueryStaticUserGroupParam iamQueryStaticUserGroupParam) {
        iamQueryStaticUserGroupParam.init();
        PageHelper.startPage(iamQueryStaticUserGroupParam.getCurrPage(),iamQueryStaticUserGroupParam.getPageSize());
        List<IamUserGroupVo> iamUserGroupVos = iamDynamicUserGroupManagerMapper.queryDynamicUserGroup(iamQueryStaticUserGroupParam);
        PageInfo<IamUserGroupVo> initPageInfo = new PageInfo<>(iamUserGroupVos);
        PageInfo<IamUserGroupVo> pageInfo = PageHelperTool.initPageInfoObj(iamQueryStaticUserGroupParam.getCurrPage(), (int) initPageInfo.getTotal(),
                iamQueryStaticUserGroupParam.getPageSize(), initPageInfo);
        return pageInfo;
    }

    /**
     * 功能描述：编辑动态用户组时，查询展示之前的数据-
     * @param iamQueryDynamicUserGroupBeforeParam
     * @return IamDynamicUserGroupVo
     * personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
     */
    @Override
    public IamDynamicUserGroupVo queryDynamicUserGroupEditBefore(IamQueryDynamicUserGroupBeforeParam iamQueryDynamicUserGroupBeforeParam) {
        IamDynamicUserGroupVo iamDynamicUserGroupVos = iamDynamicUserGroupManagerMapper.queryDynamicUserGroupEditBefore(iamQueryDynamicUserGroupBeforeParam);
        List<IamUserGroupDynamicFilterRule> filterRules = iamUserGroupDynamicFilterRuleMapper.queryuserGroupDynamicForRule(
                iamQueryDynamicUserGroupBeforeParam);

        iamDynamicUserGroupVos.setIamUserGroupDynamicFilterRules(filterRules);
        return iamDynamicUserGroupVos;
    }

    /**
     * 功能描述：编辑动态用户组
     * @param iamDynamicUserGroupEditDto
     * @return int
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void userGroupEdit(IamDynamicUserGroupEditDto iamDynamicUserGroupEditDto) {
        //编辑时，如果修改了用户组名，需要校验其唯一性
        String userGroupName = iamDynamicUserGroupManagerMapper.queryDynamicUserGroupName(iamDynamicUserGroupEditDto.getCompanyCode(),
                iamDynamicUserGroupEditDto.getUserGroupCode(),iamDynamicUserGroupEditDto.getAdminRoleCode());
        if(StringUtils.equalsIgnoreCase(userGroupName,iamDynamicUserGroupEditDto.getUserGroupName())){
            log.warn("Route=>DynamicUserGroupManagerServiceImpl method=>userGroupEdit  编辑动态用户组时没有修改用户组名");
        }else {
            //校验用户组名的唯一性
            int count = iamDynamicUserGroupManagerMapper.checkDynamicUserGroupName(iamDynamicUserGroupEditDto.getUserGroupName(),
                    iamDynamicUserGroupEditDto.getCompanyCode());
            if(count>0){
                throw new RuntimeException("该用户组名已存在，请重新编辑用户组名！");
            }
        }
        //编辑动态用户组
        int editDynamicUserGroup = iamDynamicUserGroupManagerMapper.userGroupEdit(iamDynamicUserGroupEditDto);
        if(0==editDynamicUserGroup) {
            throw new RuntimeException("编辑动态用户组失败！");
        }

        try {
            //编辑动态用户规则
            //①编辑前删除该用户组下的旧数据
            IamStaticUserGroupDeleteParam iamStaticUserGroupDeleteParam=new IamStaticUserGroupDeleteParam();
            BeanUtils.copyProperties(iamDynamicUserGroupEditDto,iamStaticUserGroupDeleteParam);
            iamUserGroupDynamicFilterRuleMapper.userGroupDynamicFilterRuleADelete(iamStaticUserGroupDeleteParam);
            iamDynamicUserGroupEditDto.getIamUserGroupDynamicFilterRules().forEach(rule ->{
                //②校验每一行的3个筛选字段都不能为空
                if(StringUtils.isBlank(rule.getRuleField())){
                    throw new RuntimeException("筛选的字段不可为空！");
                }
                if(StringUtils.isBlank(rule.getRuleCondition())){
                    throw new RuntimeException("筛选的条件不可为空！");
                }
                if(StringUtils.isBlank(rule.getRuleValue())){
                    throw new RuntimeException("筛选的值不可为空！");
                }
                //③编辑即删除旧数据，新增最新数据
                IamDynamicUserGroupFilterRuleAddDto ruleAddDto = new IamDynamicUserGroupFilterRuleAddDto();
                BeanUtils.copyProperties(rule,ruleAddDto);
                BeanUtils.copyProperties(iamDynamicUserGroupEditDto,ruleAddDto);
                iamUserGroupDynamicFilterRuleMapper.userGroupDynamicFilterRuleAdd(ruleAddDto);
            });
        }catch (Exception e) {
            log.error("Route=>DynamicUserGroupManagerServiceImpl method=>userGroupEdit 编辑动态用户组时异常：{}",e.getMessage());
            throw new RuntimeException("编辑动态用户组异常！"+e.getMessage());
        }

    }

    /**
     * 功能描述：获取某组织类型下的组织树
     * @param iamOrgInfoQueryDto
     * @return Result
     */
    @Override
    public List<OrgThreeInfoVo> getOrgTypeInfo(IamOrgInfoQueryDto iamOrgInfoQueryDto) {
        Result<List<OrgThreeInfoVo>> result = iamRoleManagerFeign.getOrgTypeInfo(iamOrgInfoQueryDto);
        List<OrgThreeInfoVo> OrgThreeInfoVos = result.getData();
        if(StringUtils.isNotBlank(iamOrgInfoQueryDto.getQueryOrgParam())){
            filterByOrg(OrgThreeInfoVos,iamOrgInfoQueryDto.getQueryOrgParam());
        }
        return Objects.requireNonNull(OrgThreeInfoVos);
    }

    /**
     * 功能描述：递归方法：获取查询参数搜索组织树
     * @param list 任意层级的节点
     * @param keyword 关键字
     */
    private void filterByOrg(List<OrgThreeInfoVo> list, String keyword){
        Iterator<OrgThreeInfoVo> parent  = list.iterator();
        while (parent.hasNext()){
            //当前节点
            OrgThreeInfoVo t = parent.next();
            if (StringUtils.isNotEmpty(keyword) && !t.getName().contains(keyword)) {
                //当前节点不包含关键字，继续遍历下一级
                // 取出下一级节点
                List<OrgThreeInfoVo> children = t.getChildrenOrgs();
                // 递归
                if (!CollectionUtils.isEmpty(children)) {
                    filterByOrg(children, keyword);
                }
                //下一级节点都被移除了，那么父节点也移除，因为父节点也不包含关键字
                if (CollectionUtils.isEmpty(t.getChildrenOrgs())) {
                    parent.remove();
                }
            } else {
                //当前节点包含关键字，继续递归遍历
                //子节点递归如果不包含关键字则会进入if分支被删除
                List<OrgThreeInfoVo> children = t.getChildrenOrgs();
                // 递归
                if (!CollectionUtils.isEmpty(children)) {
                    filterByOrg(children, keyword);
                }
            }
        }
    }

    /**
     * 功能描述：查询动态用户组下的用户（分页展示）
     * @param iamQueryDynamicUserGroupUsersParam
     * @return List
     */
    @Override
    public PageInfo<IamUserInfoVo> queryDynamicUserGroupUserInfo(IamQueryDynamicUserGroupUsersParam iamQueryDynamicUserGroupUsersParam) {
        // 该动态用户组下的筛选规则条件
        List<IamUserGroupDynamicFilterRuleVo> filterRules = iamUserGroupDynamicFilterRuleMapper.queryDynamicUserGroupUserInfo(iamQueryDynamicUserGroupUsersParam);

        IamFilterRulesParam iamFilterRulesParam = new IamFilterRulesParam();
        iamFilterRulesParam.setFilterRules(filterRules);
        iamFilterRulesParam.setCurrPage(iamQueryDynamicUserGroupUsersParam.getCurrPage());
        iamFilterRulesParam.setPageSize(iamQueryDynamicUserGroupUsersParam.getPageSize());

        Result<IamUserInfoVo> result = iamRoleManagerFeign.queryDynamicUserGroupUserInfo(iamFilterRulesParam);


        return null;
    }

}
